package com.ys.nms.module.business.service.companyproperty;

import com.baomidou.dynamic.datasource.annotation.Slave;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.ys.nms.framework.common.pojo.PageResult;
import com.ys.nms.framework.common.util.object.BeanUtils;
import com.ys.nms.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.ys.nms.framework.tenant.core.aop.TenantIgnore;
import com.ys.nms.module.business.controller.admin.alerts.vo.AlertsPageReqVO;
import com.ys.nms.module.business.controller.admin.companyProperty.vo.CompanyPropertyPageReqVO;
import com.ys.nms.module.business.controller.admin.companyProperty.vo.CompanyPropertyRespVO;
import com.ys.nms.module.business.controller.admin.companyProperty.vo.CompanyPropertySaveReqVO;
import com.ys.nms.module.business.controller.admin.devices.vo.DevicesPageReqVO;
import com.ys.nms.module.business.controller.admin.processors.vo.ProcessorsPageReqVO;
import com.ys.nms.module.business.dal.dataobject.alerts.AlertsDO;
import com.ys.nms.module.business.dal.dataobject.companyproperty.CompanyPropertyDO;
import com.ys.nms.module.business.dal.dataobject.devices.DevicesDO;
import com.ys.nms.module.business.dal.dataobject.processors.ProcessorsDO;
import com.ys.nms.module.business.dal.dataobject.storage.StorageDO;
import com.ys.nms.module.business.dal.mysql.companyproperty.CompanyPropertyMapper;
import com.ys.nms.module.business.dal.mysql.devices.DevicesMapper;
import com.ys.nms.module.business.libreApi.devices.LibreNmsDeviceClient;
import com.ys.nms.module.business.libreApi.devices.req.DeviceAddRequest;
import com.ys.nms.module.business.libreApi.devices.req.DeviceUpdateRequest;
import com.ys.nms.module.business.libreApi.devices.req.LibreNmsDevice;
import com.ys.nms.module.business.libreApi.devices.resp.LibreNmsResponse;
import com.ys.nms.module.business.service.alerts.AlertsService;
import com.ys.nms.module.business.service.devices.DevicesService;
import com.ys.nms.module.business.service.mempools.MempoolsService;
import com.ys.nms.module.business.service.processors.ProcessorsService;
import com.ys.nms.module.business.service.storage.StorageService;
import com.ys.nms.module.system.service.dept.DeptService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import jakarta.annotation.Resource;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static com.ys.nms.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.ys.nms.module.business.enums.ErrorCodeConstants.COMPANY_PROPERTY_NOT_EXISTS;


/**
 * 资产 Service 实现类
 *
 * @author 超级管理员
 */
@Service
@Validated
@RequiredArgsConstructor
public class CompanyPropertyServiceImpl implements CompanyPropertyService {

    private final LibreNmsDeviceClient deviceClient;

    @Resource
    private CompanyPropertyMapper companyPropertyMapper;

    @Resource
    private DevicesService devicesService;

    @Resource
    private DevicesMapper devicesMapper;

    @Resource
    private ProcessorsService processorsService;

    @Resource
    private StorageService storageService;

    @Resource
    private MempoolsService mempoolsService;

    @Resource
    private AlertsService alertsService;

    @Resource
    private DeptService deptService;

    /**
     * 为特定客户添加设备
     */
    public void addDeviceForClient(String hostname, String community) {

    }


    @Override
    public Integer createCompanyProperty(CompanyPropertySaveReqVO createReqVO) {
        // 插入
        CompanyPropertyDO companyPropertyDO = BeanUtils.toBean(createReqVO, CompanyPropertyDO.class);


        DeviceAddRequest addRequest = BeanUtils.toBean(createReqVO.getLibreDevice(), DeviceAddRequest.class);
        addRequest.setHostname(createReqVO.getHostName());

        // 会自动使用当前激活profile的配置
        LibreNmsResponse<LibreNmsDevice> response = deviceClient.addDevice(addRequest);

        if ("ok".equals(response.getStatus())) {

            //
            LibreNmsDevice device = response.getDevices().get(0);
            Integer deviceId = device.getDeviceId();
            companyPropertyDO.setId(deviceId);
            companyPropertyMapper.insert(companyPropertyDO);
            System.out.println("设备添加成功，使用profile: {}" + deviceClient.getCurrentConfigInfo().get("profile"));
        } else {
            if (response.getMessage().contains("already exists")) {
                throw exception("添加失败：" + response.getMessage() + ",该IP已存在");
            }

            if (response.getMessage().contains("Could not ping")) {
                throw exception("添加失败：" + response.getMessage() + ",请检查IP地址是否有误");
            }

            throw exception("添加失败：" + response.getMessage());
        }

        // 返回
        return companyPropertyDO.getId();
    }

    @Override
    public void updateCompanyProperty(CompanyPropertySaveReqVO updateReqVO) {
        // 校验存在
        validateCompanyPropertyExists(updateReqVO.getId());

        //转为更新需要的格式
        Map<String, List<String>> updateFields = toUpdateFields(updateReqVO.getLibreDevice());

        //构造请求体
        DeviceUpdateRequest updateRequest = new DeviceUpdateRequest();
        updateRequest.setField(updateFields.get("field"));
        updateRequest.setData(updateFields.get("data"));
        // 会自动使用当前激活profile的配置
        LibreNmsResponse<Void> response = deviceClient.updateDeviceFields(updateReqVO.getHostName(), updateRequest);

        if ("ok".equals(response.getStatus())) {
            // 更新
            CompanyPropertyDO updateObj = BeanUtils.toBean(updateReqVO, CompanyPropertyDO.class);
            companyPropertyMapper.updateById(updateObj);
        } else {
            throw exception("修改失败：" + response.getMessage());
        }

    }

    @Override
    public void deleteCompanyProperty(Integer id) {
        // 校验存在
        validateCompanyPropertyExists(id);
        CompanyPropertyDO companyPropertyDO = companyPropertyMapper.selectById(id);
        LibreNmsResponse<Void> response = deviceClient.deleteDevice(companyPropertyDO.getHostName());

        if ("ok".equals(response.getStatus())) {
            // 删除
            companyPropertyMapper.deleteById(id);
        } else {
            throw exception("删除失败：" + response.getMessage());
        }

    }

    @Override
    public void deleteCompanyPropertyListByIds(List<Integer> ids) {
        // 删除
        companyPropertyMapper.deleteByIds(ids);
    }


    private void validateCompanyPropertyExists(Integer id) {
        if (companyPropertyMapper.selectById(id) == null) {
            throw exception(COMPANY_PROPERTY_NOT_EXISTS);
        }
    }


    public CompanyPropertyRespVO getCompanyPropertyback(Integer id) {
        CompanyPropertyDO companyPropertyDO = companyPropertyMapper.selectById(id);
        LibreNmsResponse<LibreNmsDevice> response = deviceClient.getDeviceByHostname(companyPropertyDO.getHostName());
        CompanyPropertyRespVO respVO = BeanUtils.toBean(companyPropertyDO, CompanyPropertyRespVO.class);

        DeviceAddRequest libreDevice = new DeviceAddRequest();

        List<LibreNmsDevice> deviceList = response.getDevices();
        if (deviceList != null && !deviceList.isEmpty()) {
            libreDevice = BeanUtils.toBean(deviceList.getFirst(), DeviceAddRequest.class);
            System.out.println(libreDevice);
            respVO.setLibreDevice(libreDevice);
        }
        respVO.setLibreDevice(libreDevice);

        return respVO;
    }

    @Override
    public CompanyPropertyRespVO getCompanyProperty(Integer id) {
        CompanyPropertyDO companyPropertyDO = companyPropertyMapper.selectById(id);
        CompanyPropertyRespVO respVO = BeanUtils.toBean(companyPropertyDO, CompanyPropertyRespVO.class);
        DeviceAddRequest libreDevice = new DeviceAddRequest();
        DevicesDO devices = devicesService.getDevices(id);

        checkSnmp(devices);

        //http://172.30.30.93:8000/images/os/fortinet.svg
        //设置完整icon

        String currentUrl = deviceClient.getCurrentUrl() + "/images/os/" + devices.getIcon();
        System.out.println("currentUrl: " + currentUrl);
        devices.setIcon(currentUrl);

        respVO.setDevices(devices);
        if (devices != null) {
            libreDevice = BeanUtils.toBean(devices, DeviceAddRequest.class);
            System.out.println(libreDevice);
            respVO.setLibreDevice(libreDevice);
        }
        respVO.setLibreDevice(libreDevice);

        //1.取告警数量 24小时内告警和历史告警总数
        AlertsPageReqVO alertsVO24 = new AlertsPageReqVO();
        alertsVO24.setDeviceId(id);
        //获取当前时间
        LocalDateTime now = LocalDateTime.now();
        // 获取24小时前的时间
        LocalDateTime twentyFourHoursAgo = now.minusHours(24);
        // 创建时间数组
        LocalDateTime[] timestamps = new LocalDateTime[]{twentyFourHoursAgo, now};
        // 设置到 VO 中
        alertsVO24.setTimestamp(timestamps);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        //24小时以内的
        List<AlertsDO> alertsList24 = alertsService.getAlertsListByDeviceId(alertsVO24);
        respVO.setAlertDay(alertsList24.size());

        LocalDateTime[] timestampTotal = new LocalDateTime[]{
                LocalDateTime.of(2000, 1, 1, 0, 0, 0),  // 开始时间：2000年1月1日
                LocalDateTime.now()                   // 结束时间：当前时间
        };
        alertsVO24.setTimestamp(timestampTotal);
        //总的
        List<AlertsDO> alertsListTotal = alertsService.getAlertsListByDeviceId(alertsVO24);
        respVO.setAlertTotal(alertsListTotal.size());

        //2.取cpu利用率和内存利用率
        Double cpuUsage = processorsService.getCpuUsage(id);
        respVO.setCpuUsage(cpuUsage);

        Double systemMempools = mempoolsService.getSystemMempoolsByDeviceId(id);
        respVO.setMemUsage(systemMempools);

        //3.获取ping延迟数据 从新的接口获取


        //4.取存储表
        List<StorageDO> storageList = storageService.getStorageListByDeviceId(id);
        respVO.setStorageList(storageList);

        return respVO;

    }


    public void syncData() {
        LambdaQueryWrapper<DevicesDO> queryWrapper = new LambdaQueryWrapper<>();

        LambdaQueryWrapper<CompanyPropertyDO> propertyWrapper = new LambdaQueryWrapper<>();

        List<DevicesDO> devicesDOS = devicesService.getDevicesList();
        List<CompanyPropertyDO> list = new ArrayList<>();
        for (DevicesDO devicesDO : devicesDOS) {
            propertyWrapper.eq(CompanyPropertyDO::getId, devicesDO.getDeviceId());
            if (!companyPropertyMapper.exists(propertyWrapper)) {
                CompanyPropertyDO insertCompanyProperty = new CompanyPropertyDO();
                insertCompanyProperty.setId(devicesDO.getDeviceId());
                insertCompanyProperty.setHostName(devicesDO.getHostname());
                insertCompanyProperty.setName(devicesDO.getSysName());
                insertCompanyProperty.setArea(2L);
                list.add(insertCompanyProperty);
            }


        }
        if (!list.isEmpty()) {
            companyPropertyMapper.insertBatch(list);
        }


    }

    //判断是否仅ping
    public void checkSnmp(DevicesDO devices) {
        //判断是否是pingOnly
        if (StringUtils.isNotEmpty(devices.getCommunity()) && devices.getSnmpDisable() == 0 && devices.getStatus() == 1 && devices.getDisabled() == 0) {
            devices.setShowMore(true);
        } else {
            devices.setShowMore(false);
        }

    }

    @Override
    public PageResult<CompanyPropertyDO> getCompanyPropertyPage(CompanyPropertyPageReqVO pageReqVO) {
        // 1. 先查询从数据源设备表

        List<Integer> deviceIds = devicesService.selectDeviceIds(pageReqVO);

        // 3. 再查询主数据源表
        LambdaQueryWrapperX<CompanyPropertyDO> propertyWrapperX = new LambdaQueryWrapperX<CompanyPropertyDO>();
        propertyWrapperX.likeIfPresent(CompanyPropertyDO::getHostName, pageReqVO.getHostName());
        propertyWrapperX.likeIfPresent(CompanyPropertyDO::getName, pageReqVO.getName());
        propertyWrapperX.eqIfPresent(CompanyPropertyDO::getDeviceType, pageReqVO.getDeviceType());
        propertyWrapperX.eqIfPresent(CompanyPropertyDO::getArea, pageReqVO.getArea());
        propertyWrapperX.select(CompanyPropertyDO::getId);
        List<CompanyPropertyDO> propertyList = companyPropertyMapper.selectList(propertyWrapperX);
        List<Integer> propertyIds = propertyList.stream()
                .map(CompanyPropertyDO::getId)
                .collect(Collectors.toList());
        // 4. 数据组装
        propertyIds.add(0);

        List<Integer> intersection = deviceIds.stream()
                .filter(propertyIds::contains)  // 筛出在 resultIds 中存在的
                .collect(Collectors.toList());

        System.out.println("交集: " + intersection);
        pageReqVO.setIdList(intersection);

        PageResult<CompanyPropertyDO> pageResult = companyPropertyMapper.selectPage(pageReqVO);
        pageResult.getList().forEach(propertyDO -> {
            //1.取cpu利用率
            Integer id = propertyDO.getId();
            Double cupUsage = processorsService.getCpuUsage(id);
            propertyDO.setCpuUsage(cupUsage);

            //2.取内存利用率
            Double systemMempools = mempoolsService.getSystemMempoolsByDeviceId(id);
            propertyDO.setMemUsage(systemMempools);

            //3.取明细
            DevicesDO devices = devicesService.getDevices(id);
            propertyDO.setDevices(devices);


        });

        return pageResult;
    }

    @Override
    public void updateDevice(DeviceAddRequest updateReqVO) {
        //转为更新需要的格式
        Map<String, List<String>> updateFields = toUpdateFields(updateReqVO);

        //构造请求体
        DeviceUpdateRequest updateRequest = new DeviceUpdateRequest();
        updateRequest.setField(updateFields.get("field"));
        updateRequest.setData(updateFields.get("data"));
        // 会自动使用当前激活profile的配置
        LibreNmsResponse<Void> response = deviceClient.updateDeviceFields(updateReqVO.getHostname(), updateRequest);

        if ("ok".equals(response.getStatus())) {
            // 更新
        } else {
            throw exception("修改失败：" + response.getMessage());
        }
    }


    public static Map<String, List<String>> toUpdateFields(DeviceAddRequest request) {
        List<String> fields = new ArrayList<>();
        List<String> data = new ArrayList<>();

        // 现在可以直接传 Integer、String、
        addIfNotNull(fields, data, "snmp_ver", request.getSnmpver());
        addIfNotNull(fields, data, "port_association_mode", request.getPortAssociationMode());
        addIfNotNull(fields, data, "ping_fallback", request.getPing_fallback());
        addIfNotNull(fields, data, "port", request.getPort());
        addIfNotNull(fields, data, "transport", request.getTransport());
        addIfNotNull(fields, data, "snmp_disable", request.getSnmpDisable());
        addIfNotNull(fields, data, "disabled", request.getDisabled());
        addIfNotNull(fields, data, "authlevel", request.getAuthlevel());
        addIfNotNull(fields, data, "authname", request.getAuthname());
        addIfNotNull(fields, data, "authpass", request.getAuthpass());
        addIfNotNull(fields, data, "authalgo", request.getAuthalgo());
        addIfNotNull(fields, data, "cryptopass", request.getCryptopass());
        addIfNotNull(fields, data, "cryptoalgo", request.getCryptoalg());
        addIfNotNull(fields, data, "sysName", request.getSysName());
        addIfNotNull(fields, data, "hardware", request.getHardware());
        addIfNotNull(fields, data, "community", request.getCommunity());


        Map<String, List<String>> result = new HashMap<>();
        result.put("field", fields);
        result.put("data", data);

        return result;
    }

    private static void addIfNotNull(List<String> fields, List<String> data, String fieldName, Object value) {
        if (value != null) {
            fields.add(fieldName);
            data.add(value.toString()); // 所有非 null 对象转为字符串
        }
    }


}